﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace Bamboo.CodeCat
{
    /// <summary>
    /// 翻译宏，指向某个特定类的成员方法或属性

    /// </summary>
    public class Macro
    {
        /// <summary>
        /// 宏名称，不带@符号
        /// </summary>
        public string Name { get; }
        /// <summary>
        /// 宏全称，带@符号
        /// </summary>
        public string FullName { get; }
        /// <summary>
        /// 目前支持三种风格的翻译宏：
        /// 1. string GetXXX();  //返回string的翻译方法
        /// 2. void GetXXX(StringBuilder s);    //将翻译后的值填入StringBuilder
        /// 3. string XXX { get { return ...; } };   //返回string的属性
        /// </summary>
        public int Style { get; }
        /// <summary>
        /// 宏所对应的翻译类型
        /// </summary>
        public Type Type { get; }

        public MemberInfo MemberInfo { get; }
        /// <summary>
        /// 对于风格1和2，由本属性保存对应的翻译方法信息
        /// </summary>
        public MethodInfo MethodInfo { get; }
        /// <summary>
        /// 对于风格3，由本属性保存对应的属性信息
        /// </summary>
        public PropertyInfo PropertyInfo { get; }

        public Macro(MemberInfo member, MacroAttribute attribute)
        {
            this.Type = member.DeclaringType;
            this.Name = string.IsNullOrWhiteSpace(attribute.MacroName) ? member.Name : attribute.MacroName;
            this.FullName = "@" + Name + "@";
            this.MemberInfo = member;
            //识别风格
            if (this.MemberInfo.MemberType == MemberTypes.Method)
            {   //风格1或2
                this.MethodInfo = this.Type.GetMethod(this.MemberInfo.Name);
                if (this.MethodInfo == null)
                {
                    throw new Exception("初始化翻译宏失败，根据方法名称找不到类方法，类：" +
                        this.Type.FullName + "，成员：" + member.Name);
                }
                
                if (!this.MethodInfo.IsStatic && this.MethodInfo.IsPublic && !this.MethodInfo.IsGenericMethod &&
                    this.MethodInfo.GetParameters().Length == 0 && 
                    this.MethodInfo.ReturnParameter.ParameterType != typeof(void))
                {   //风格1：string GetXXX();
                    this.Style = 1;
                }
                else if (!this.MethodInfo.IsStatic && this.MethodInfo.IsPublic && !this.MethodInfo.IsGenericMethod &&
                    this.MethodInfo.GetParameters().Length == 1 && 
                    this.MethodInfo.GetParameters()[0].ParameterType == typeof(StringBuilder) &&
                    this.MethodInfo.ReturnParameter.ParameterType == typeof(void))
                {   //风格2：void GetXXX(StringBuilder s);
                    this.Style = 2;
                }
                else 
                {
                    throw new Exception("初始化翻译宏失败，翻译方法的声明形式不符合要求，类：" +
                        this.Type.FullName + "，成员：" + member.Name + "，方法：" + this.MethodInfo);
                }
            }
            else if (this.MemberInfo.MemberType == MemberTypes.Property)
            {   //风格3：string XXX { get { return ...; } };
                this.PropertyInfo = this.Type.GetProperty(this.MemberInfo.Name);
                if (this.PropertyInfo == null)
                {
                    throw new Exception("初始化翻译宏失败，根据名称找不到类属性，类：" +
                        this.Type.FullName + "，成员：" + member.Name);
                }
                if (this.PropertyInfo.CanRead && 
                    this.PropertyInfo.GetIndexParameters().Length == 0)
                {
                    this.Style = 3;
                }
                else
                {
                    throw new Exception("初始化翻译宏失败，属性的声明形式不符合要求，类：" +
                        this.Type.FullName + "，成员：" + member.Name + "，属性：" + this.PropertyInfo);
                }
            }
            else
            {
                throw new Exception("初始化翻译宏失败，类成员的成员类型错误，类：" +
                    this.Type.FullName + "，成员：" + member.Name + "，成员类型：" + this.MemberInfo.MemberType);
            }
        }

        public void GetValue(object instance, StringBuilder output)
        {
            if (Style == 1)
            {   //风格1：string GetXXX();
                var ret = this.MethodInfo.Invoke(instance, null).ToString();
                output.Append(ret);
            }
            else if (Style == 2)
            {   //风格2：void GetXXX(StringBuilder s);
                this.MethodInfo.Invoke(instance, new object[] { output });
            }
            else if (Style == 3)
            {   //风格3：string XXX { get { return ...; } };
                var ret = this.PropertyInfo.GetValue(instance).ToString();
                output.Append(ret);
            }
            else
            {
                throw new Exception("不支持的方法风格，类：" + Type + "，成员：" + MemberInfo + "，风格：" + Style);
            }
        }
    }
}
